﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;
using System.Drawing.Design;

[assembly: WebResource("wpCumulus.swfobject.js", "text/javascript")]
[assembly: WebResource("wpCumulus.tagcloud.swf", "application/x-shockwave-flash")]

namespace wpCumulus
{
    /// <summary>
    /// Flash based tag cloud wrapped in server side ASP.NET control.
    /// For additional information see http://wordpress.org/extend/plugins/wp-cumulus/.
    /// </summary>
    [ToolboxData("<{0}:WPCumulus runat=server></{0}:WPCumulus>")]
    public class WPCumulus : DataBoundControl
    {
        private const int m_RequiredFlashVersion = 9;

        /// <summary>
        /// Color of the tags.
        /// </summary>
        [Bindable(true)]
        [Category("Appearance")]
        [Editor(typeof(ColorEditor), typeof(UITypeEditor))]
        [DefaultValue(typeof(Color), "0x995500")]
        [Description("Color of the tags.")]
        public Color TagColor1
        {
            get
            {
                object o = ViewState["TagColor1"];
                if(o == null)
                    return ColorTranslator.FromHtml("0x995500");
                return (Color)o;
            }
            set { ViewState["TagColor1"] = value; }
        }

        /// <summary>
        /// Optional second color for gradient.
        /// </summary>
        [Bindable(true)]
        [Category("Appearance")]
        [Editor(typeof(ColorEditor), typeof(UITypeEditor))]
        [DefaultValue(typeof(Color), "0x333333")]
        [Description("Optional second color for gradient.")]
        public Color TagColor2
        {
            get
            {
                object o = ViewState["TagColor2"];
                if (o == null)
                    return ColorTranslator.FromHtml("0x333333");
                return (Color)o;
            }
            set { ViewState["TagColor2"] = value; }
        }

        /// <summary>
        /// Optional highlight color.
        /// </summary>
        [Bindable(true)]
        [Category("Appearance")]
        [Editor(typeof(ColorEditor), typeof(UITypeEditor))]
        [DefaultValue(typeof(Color), "0x000000")]
        [Description("Optional highlight color.")]
        public Color HiColor
        {
            get
            {
                object o = ViewState["HiColor"];
                if (o == null)
                    return ColorTranslator.FromHtml("0x000000");
                return (Color)o;
            }
            set { ViewState["HiColor"] = value; }
        }

        /// <summary>
        /// Rotation speed of tag cloud.
        /// </summary>
        [Bindable(true)]
        [Category("Appearance")]
        [Description("Rotation speed of tag cloud.")]
        public int TagSpeed
        {
            get
            {
                object o = ViewState["TagSpeed"];
                if (o == null)
                    return 100;
                return (int)o;
            }
            set { ViewState["TagSpeed"] = value; }
        }

        /// <summary>
        /// Distribute tags evenly on sphere.
        /// </summary>
        [Bindable(true)]
        [Category("Appearance")]
        [Description("Distribute tags evenly on sphere.")]
        public bool Distr
        {
            get
            {
                object o = ViewState["Distr"];
                if (o == null)
                    return true;
                return (bool)o;
            }
            set { ViewState["Distr"] = value; }
        }

        [Bindable(true)]
        [DefaultValue(20)]
        [Category("Appearance")]
        public virtual int MaximumTagSize
        {
            get
            {
                object o = ViewState["MaximumTagSize"];
                if (o == null)
                    return 20;
                return (int)o;
            }
            set
            {
                if (value < MinimumTagSize)
                    throw new ArgumentException("Property value MaximumTagSize cannot be less than MaximumTagSize.");

                ViewState["MaximumTagSize"] = value;
            }
        }

        [Bindable(true)]
        [DefaultValue(10)]
        [Category("Appearance")]
        public virtual int MinimumTagSize
        {
            get
            {
                object o = ViewState["MinimumTagSize"];
                if (o == null)
                    return 10;
                return (int)o;
            }
            set
            {
                if(value > MaximumTagSize)
                    throw new ArgumentException("Property value MinimumTagSize cannot be greater than MaximumTagSize.");

                ViewState["MinimumTagSize"] = value;
            }
        }

        [Bindable(true)]
        [Category("Databinding")]
        public virtual string  DataTextField
        {
            get
            {
                object o = ViewState["DataTextField"];
                if (o == null)
                    return String.Empty;
                return (string)o;
            }
            set { ViewState["DataTextField"] = value; }
        }

        [Bindable(true)]
        [Category("Databinding")]
        public virtual string DataUrlField
        {
            get
            {
                object o = ViewState["DataUrlField"];
                if (o == null)
                    return String.Empty;
                return (string)o;
            }
            set { ViewState["DataUrlField"] = value; }
        }

        [Bindable(true)]
        [Category("Databinding")]
        public virtual string DataCountField
        {
            get
            {
                object o = ViewState["DataCountField"];
                if (o == null)
                    return String.Empty;
                return (string)o;
            }
            set { ViewState["DataCountField"] = value; }
        }

       
  
        string CreateScriptString(string tagCloud, string hiddenContentId)
        {
            var sb = new StringBuilder();
            var moviePath = Page.ClientScript.GetWebResourceUrl(typeof (WPCumulus), "wpCumulus.tagcloud.swf");

            sb.AppendFormat("var widget_so = new SWFObject('{0}', 'tagcloudflash', '{1}', '{2}', '{3}', '#{4}');",
                moviePath, 
                Width, 
                Height, 
                m_RequiredFlashVersion, 
                BackColor.ToHtml());

            sb.Append("widget_so.addParam('allowScriptAccess', 'always');");
            sb.Append("widget_so.addVariable( 'mode' , 'tags' );");

            sb.AppendFormat("widget_so.addVariable( \"tcolor\"  , \"0x{0}\" );", TagColor1.ToHtml());
            sb.AppendFormat("widget_so.addVariable( \"tcolor2\" , \"0x{0}\" );", TagColor2.ToHtml());
            sb.AppendFormat("widget_so.addVariable( \"hicolor\" , \"0x{0}\" );", HiColor.ToHtml());
            sb.AppendFormat("widget_so.addVariable( \"tspeed\"  , \"{0}\" );", TagSpeed);
            sb.AppendFormat("widget_so.addVariable( \"distr\"   , \"{0}\" );", Distr.ToString().ToLowerInvariant());
            sb.AppendFormat("widget_so.addVariable( \"tagcloud\", \"{0}\" );", tagCloud);
            sb.AppendFormat("widget_so.addVariable( \"compmode\", \"{0}\" );", true);
            sb.AppendFormat("widget_so.addVariable( \"trans\", \"{0}\" );", true); // Use transparent mode

            
            sb.AppendFormat("widget_so.write('{0}');", hiddenContentId);

            return sb.ToString();
        }

        protected override void CreateChildControls()
        {
            ClearChildViewState();
            Controls.Clear();
            Page.ClientScript.RegisterClientScriptResource(GetType(), "wpCumulus.swfobject.js");
        }

        protected override void RenderContents(HtmlTextWriter output)
        {
            if (DesignMode)
            {
                base.RenderContents(output);
            }
            else
            {
                var hiddenContentId = ClientID + ClientIDSeparator + "HiddenContent";

                var tagCloud = GenerateTagCloud();
                var script = CreateScriptString(tagCloud, hiddenContentId);

                output.Write(String.Format("<div id=\"{0}\"></div>", hiddenContentId));
                output.Write("<script type=\"text/javascript\">");
                output.Write(script);
                output.Write("</script>");
            }
        }

        /// <summary>
        /// This field contains well-formed for wpCumulus tag content string.
        /// </summary>
        private string m_WellFormedTagCloud;
        
        private string GenerateTagCloud()
        {
            return m_WellFormedTagCloud;
        }

        protected override void PerformDataBinding(System.Collections.IEnumerable dataSource)
        {
            base.PerformDataBinding(dataSource);

            if(DesignMode)
                return;
            
            var items = new List<object>();
            foreach (var o in dataSource)
            {
                items.Add(o);
            }

            if(dataSource != null)
            {
                var res = from item in items
                           select new
                                     {
                                         Url = (string)DataBinder.GetPropertyValue(item, DataUrlField),
                                         Title = (string) DataBinder.GetPropertyValue(item, DataTextField),
                                         Count = Convert.ToDouble(DataBinder.GetPropertyValue(item, DataCountField))
                                     };

                var minCount = (from item in res select item.Count).Min();
                var maxCount = (from item in res select item.Count).Max();

                var weightDiff = maxCount - minCount;

                double minSize = MinimumTagSize;
                double maxSize = MaximumTagSize;

                var sb = new StringBuilder();
                sb.Append(HttpUtility.UrlEncode("<tags>"));

                foreach (var item in res)
                {
                    // Calculate font size depending tag weight:
                    int fontSize = (int) (minSize + (maxSize - minSize)*(item.Count - minCount)/weightDiff);

                    var line = string.Format("<a href='{0}' title='{1} topics' rel=\"tag\" style='font-size:{2}pt;'>{3}</a>",
                        item.Url,
                        item.Count, 
                        fontSize,
                        HttpUtility.HtmlEncode(item.Title));

                    var encodedLine = HttpUtility.UrlEncode(line).Replace(' ', '+');
                    sb.Append(encodedLine);
                }
                sb.Append(HttpUtility.UrlEncode("</tags>"));

                m_WellFormedTagCloud = sb.ToString();
            }
        }

    
    }
}